package com.comboo.example.web.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author Sherman
 * created in 2018/12/20 2018
 */
@Slf4j
@Component
@Aspect
public class MyHandlerResponseLogger {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.PostMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.PutMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.DeleteMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.PatchMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.RequestMapping)||" +
            "@annotation(org.springframework.web.bind.annotation.ExceptionHandler)")
    private void handlerMethod() {
    }

    @AfterReturning(pointcut = "handlerMethod()", returning = "returnObj")
    public void logAfterReturn(JoinPoint jp, Object returnObj) {

        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        if (request == null) {
            // 非请求类型的调用（例如直接调用controller方法），不进行参数信息提取。
            return;
        }
        try {
            doResponseLog(request, jp, returnObj);
        } catch (Exception ex) {
            log.warn("日志切面出现问题，导致无法正常记录日志。请检查异常（见下文）。本异常已被捕获，不会影响方法本身的调用", ex);
        }
    }

    private void doResponseLog(HttpServletRequest request, JoinPoint jp, Object returnObj) throws JsonProcessingException {
        Map<String, Object> map = new HashMap<>();
        map.put("请求地址", request.getRequestURL());
        map.put("返回参数", returnObj);
        log.info("响应内容：\n" + OBJECT_MAPPER.writeValueAsString(map));
    }
}
